TML-2785: M:N slice 1 — correlated include read through the junction#679
Conversation
…ndard (TML-2785) Read slice (correlated include through junction). Bakes the operator integration-test standard (whole-row asserts, explicit select, +implicit nested-M:N case) into the project cross-cutting requirements and slice 1. 3 dispatches: fixture M:N / read code / integration tests. Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
…re-emit contract Adds a pure-junction UserTag model (userId/tagId, composite PK) and a User.tags manyToMany relation to the sql-orm-client integration fixture. Re-emits contract.json + contract.d.ts for both the integration test copy and the package-local copy (with pgvector refs stripped). The Tag model stays single-sided (no Tag.users reverse) to avoid a MutationCreateInputWithRelations overload collision in the existing collection-mutation-defaults tests. Emitted via tsx script (c12 config loader unavailable in this sandbox); verified additivity of the diff and round-trip via SqlContractSerializer. Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
Add many-to-many include support via a single correlated subquery that joins the child table to the junction on junction.childColumns = child.targetColumns and correlates to the parent via WHERE junction.parentColumns = parent.parentLocalColumns. Composite keys AND across all column pairs. No LATERAL joins. - IncludeExpr gains `through?: IncludeThroughDescriptor` carrying junction table name, parentColumns, childColumns, targetColumns, and parentLocalColumns. - `resolveIncludeRelation` in collection-contract.ts surfaces `through` from the contract relation when present, resolving field names to column names for the parent local columns. - `Collection.include()` propagates `through` into IncludeExpr via spread. - `buildManyToManyJunctionArtifacts` in query-plan-select.ts builds the JOIN ON expression (BinaryExpr or AndExpr over child column pairs) and the correlated WHERE (BinaryExpr or AndExpr over parent column pairs), producing a non-lateral inner JoinAst to the junction table. - `buildIncludeChildRowsSelect` detects `include.through` and uses the M:N artifacts instead of the FK equality WHERE; `buildDistinctNonLeafChildRowsSelect` receives and applies the same junction joins. - `dispatchWithIncludes` in collection-dispatch.ts forces all `through.parentLocalColumns` (not just `localColumn`) into the parent SELECT augmentation for composite M:N keys. - `buildManyToManyContract` test helper and M:N unit tests covering single-column and composite-key junction shapes, plus a FK path non-regression test. Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
…ManyJunctionArtifacts; add M:N+distinct+non-leaf test
F1: the two bare `as AnyExpression` casts in `buildManyToManyJunctionArtifacts` are replaced with
`castAs<AnyExpression>(…!)` — BinaryExpr is a union member of AnyExpression, so the assertion is
type-checked; the non-null assertion is safe because the branch is only taken when `length === 1`.
Adds the `castAs` import from `@prisma-next/utils/casts`. `lint:casts` delta: -1.
F2: new unit test `attaches junction join to baseInner in M:N + distinct + nested non-leaf path`
in the `M:N include correlated subquery` describe block. Constructs a contract with
parents→children (M:N via parent_child junction) + children→grandchildren (FK), sets
`distinct: ['name']` and a nested grandchild include on the M:N IncludeExpr, calls
`compileSelectWithIncludes`, and asserts:
- junction join (`INNER JOIN parent_child`, `lateral: false`) attaches to `baseInner`
(the innermost scalar SELECT inside the ROW_NUMBER wrap), not to the dedup wrapper or
outer distinct SELECT
- correlated WHERE (`parent_child.parent_id = parents.id`) is present at `baseInner`
- no junction join leaks to `innerSelect` or the outer `childRows`
All 493 tests pass; typecheck clean.
Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
Adds `mn-include.test.ts` covering the end-to-end M:N include path for
`User.tags` via the `user_tags` junction, using the PGlite harness.
Tests satisfy the operator integration-test standard:
- Whole-row toEqual assertions on every test
- Explicit .select() on 6/7 tests
- One implicit/default-selection test (full User + tags: Tag[] shape)
- Single-execution assertion + no LATERAL in emitted SQL
- Depth-2: M:N tags nested under invitedUsers (1:N self-relation)
- Sibling depth-2: include("tags") alongside include("posts") in one execution
- Edge: user with no tags returns tags: []
- Edge: tag shared by multiple users resolves independently for each
Also extends `setupTestSchema` and adds `seedTags`/`seedUserTags` helpers
to `runtime-helpers.ts` to support the junction table in integration tests.
Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
… (TML-2785) Orchestrator artifacts for the read slice (fixture / read-path / integration dispatches; read-path took 3 rounds incl. a truncation recovery). Review log under reviews/ is gitignored. Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
size-limit report 📦
|
@prisma-next/extension-author-tools
@prisma-next/mongo-runtime
@prisma-next/family-mongo
@prisma-next/sql-runtime
@prisma-next/family-sql
@prisma-next/extension-arktype-json
@prisma-next/middleware-cache
@prisma-next/mongo
@prisma-next/extension-paradedb
@prisma-next/extension-pgvector
@prisma-next/extension-postgis
@prisma-next/postgres
@prisma-next/sql-orm-client
@prisma-next/sqlite
@prisma-next/target-mongo
@prisma-next/adapter-mongo
@prisma-next/driver-mongo
@prisma-next/contract
@prisma-next/utils
@prisma-next/config
@prisma-next/errors
@prisma-next/framework-components
@prisma-next/operations
@prisma-next/ts-render
@prisma-next/contract-authoring
@prisma-next/ids
@prisma-next/psl-parser
@prisma-next/psl-printer
@prisma-next/cli
@prisma-next/cli-telemetry
@prisma-next/emitter
@prisma-next/migration-tools
prisma-next
@prisma-next/vite-plugin-contract-emit
@prisma-next/mongo-codec
@prisma-next/mongo-contract
@prisma-next/mongo-value
@prisma-next/mongo-contract-psl
@prisma-next/mongo-contract-ts
@prisma-next/mongo-emitter
@prisma-next/mongo-schema-ir
@prisma-next/mongo-query-ast
@prisma-next/mongo-orm
@prisma-next/mongo-query-builder
@prisma-next/mongo-lowering
@prisma-next/mongo-wire
@prisma-next/sql-contract
@prisma-next/sql-errors
@prisma-next/sql-operations
@prisma-next/sql-schema-ir
@prisma-next/sql-contract-psl
@prisma-next/sql-contract-ts
@prisma-next/sql-contract-emitter
@prisma-next/sql-lane-query-builder
@prisma-next/sql-relational-core
@prisma-next/sql-builder
@prisma-next/target-postgres
@prisma-next/target-sqlite
@prisma-next/adapter-postgres
@prisma-next/adapter-sqlite
@prisma-next/driver-postgres
@prisma-next/driver-sqlite
commit: |
Slice 1 of the SQL ORM: Many-to-Many End to End project (Linear project). Reads an M:N relation through its junction.
Overview
db.orm.User.include(tags)now resolves a many-to-many relation to{ …user, tags: Tag[] }in a single correlated subquery that walks parent → junction → target — noLATERAL, no second query. Built on slice 0sResolvedRelation.through.Changes (4 commits)
fcecac5b3— integration fixture gains aUser ↔ TagM:N relation via aUserTagjunction (composite PKuser_id/tag_id);contract.json/.d.tsre-emitted.e587b433c— read path:IncludeExpr.through(surfaced byresolveIncludeRelation), andbuildCorrelatedIncludeProjectiongains an M:N branch —buildManyToManyJunctionArtifactsbuilds a non-LATERAL inner join to the junction (junction.childColumns = target.targetColumns) correlated to the parent (junction.parentColumns = parentanchor), composite-key AND-ed; FK decode path reused. Unit-tested at the AST level.b9c3e9f7b— replace 2 bareascasts withcastAs; add the missing M:N + distinct + non-leaf unit test.d3232cbad— 7 integration tests (PGlite).Integration tests (per the project standard)
Whole-row
toEqual; 6/7 use explicit.select(...)(so adding a model field wont churn assertions); test 5 uses implicit/default selection (fullUser+tags: Tag[]shape); a single-execution / no-LATERALassertion; depth-2 nesting (invitedUsers → tags); edges (user with no tags →tags: []; a tag shared by multiple users).Why
This is the first of the three relation-shaped M:N consumers (read / filter / write) over slice 0s shared
throughprimitive. The correlated-only approach matches the post-TML-2729 read path (no LATERAL to reintroduce).Scope / notes
Read only — filter (TML-2786) and write (TML-2787) are later slices. The fixture is one-directional (
User.tags; reverseTag.usersdeferred — adding it trips a latent create-overload type fragility in unrelated mutation-defaults tests; see the projects unattended-decisions log). Fixture re-emit used atsxbypass because the CLIcontract emitfails on a sandbox config-load env issue — CIfixtures:checkis the real golden-stability gate; please confirm its green (or re-run the canonical emit). Broad integration runs show pre-existing PGlite/WASM JIT flakiness; the M:N tests pass on targeted runs.Refs: TML-2785.